#ifndef GAMEENGINE_GEOMETRY_POINT2D_HPP
#define GAMEENGINE_GEOMETRY_POINT2D_HPP

#include <math.h>

#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif

//=================================================================================
// Implementation of the Point2d class

//! Default constructor
/*!
 @note Class T should have a default constructor
 */
template <class T>
Point2d<T>::Point2d() {}

//! Constructor from two coordinates
/*!
 @param x The first coordinate
 @param y The second coordinate
 @note Class T should have a default constructor
 @note Class T should have an assignment operator
 */
template <class T>
Point2d<T>::Point2d(const T& x, const T& y) {
	coordinates_[0] = x;
	coordinates_[1] = y;
}

//! Copy constructor
/*!
 @param rhs The point to copy
 @note Class T should have a default constructor
 @note Class T should have an assignment operator
 */
template <class T>
Point2d<T>::Point2d(const Point2d& rhs) {
	for ( int k = 0; k < 2; ++k ) {
		coordinates_[k] = rhs.coordinates_[k];
	}
}

//! Copy constructor
/*!
 @param rhs The point to copy
 @note Class T should have a default constructor
 @note Class T should have an assignment operator
 */
template <class T>
template <class R>
Point2d<T>::Point2d(const Point2d<R>& rhs) {
	for ( int k = 0; k < 2; ++k ) {
		coordinates_[k] = (T)rhs[(Point2D::Index)k];
	}
}

//! Destructor
/*!
 @note The destructor of class T should be public
 */
template <class T>
Point2d<T>::~Point2d() {}

//! Assignment operator
/*!
 @param rhs The point to copy
 @note Class T should have an assignment operator
 */
template <class T>
Point2d<T>& Point2d<T>::operator=(const Point2d& rhs) {
	if ( &rhs != this ) {
		for ( int k = 0; k < 2; ++k ) {
			coordinates_[k] = rhs.coordinates_[k];
		}
	}
	return *this;
}

//! Accessor to the first coordinate (read-write)
/*!
 @return A reference to the first coordinate
 */
template <class T>
T& Point2d<T>::x() {
	return coordinates_[0];
}

//! Accessor to the first coordinate (read only)
/*!
 @return A constant reference to the first coordinate
 */
template <class T>
const T& Point2d<T>::x() const {
	return coordinates_[0];
}

//! Accessor to the second coordinate (read-write)
/*!
 @return A reference to the second coordinate
 */
template <class T>
T& Point2d<T>::y() {
	return coordinates_[1];
}

//! Accessor to the second coordinate (read only)
/*!
 @return A constant reference to the second coordinate
 */
template <class T>
const T& Point2d<T>::y() const {
	return coordinates_[1];
}

//! Accessor to the given coordinate (read-write)
/*!
 @param index The index of the point to access
 @return A reference to the given coordinate
 */
template <class T>
T& Point2d<T>::operator[](Point2D::Index index) {
	return coordinates_[(int)index];
}

//! Accessor to the given coordinate (read only)
/*!
 @param index The index of the point to access
 @return A constant reference to the given coordinate
 */
template <class T>
const T& Point2d<T>::operator[](Point2D::Index index) const {
	return coordinates_[(int)index];
}

//! Compute the distance between the two points
/*!
 @param rhs The point used to compute distance
 @return The distance between the two points
 @note Class T should have an implicit conversion to type double
 */
template <class T>
double Point2d<T>::get_distance(const Point2d& rhs) const {
	return sqrt( (double)get_square_distance(rhs) );
}

//! Compute the square distance between the two points
/*!
 @param rhs The point used to compute square distance
 @return The square distance between the two points
 */
template <class T>
T Point2d<T>::get_square_distance(const Point2d& rhs) const {
	return		( coordinates_[0]-rhs.coordinates_[0] ) * ( coordinates_[0]-rhs.coordinates_[0] )
			+	( coordinates_[1]-rhs.coordinates_[1] ) * ( coordinates_[1]-rhs.coordinates_[1] );
}

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#endif
